from imports import *
class reptil_comments():                # 爬取单个景区页面的所有评论
    def __init__(self):
        pass

    def get(self, url) -> list:                     # 获取页面的评论信息
        '''
            作用说明：提取某个景区的所有评论
        :param url:str
        :return:List [List, List, List, List]
        '''
        assert isinstance(url, str), '参数url必须为string类型.'

        self.id = self.getId(url)                               # 获取景区ID
        print('已找到景区网址的id号: ' + str(self.id))           # 提示信息
        self.CommentNum = self.getCommentNum(url)               # 获取评论数
        self.PageNum = math.ceil(int(self.CommentNum) / 50)     # 获取分页数、每页50条评论
        URL = 'https://m.ctrip.com/restapi/soa2/13444/json/getCommentCollapseList?_fxpcqlniredt=09031' \
              '073114492803259&x-traceID=09031073114492803259-1623339271143-2357283'
                                                                # 携程评论页面必备URL，无需修改

        content, images, score, publishTime = [], [], [], []    # 存储评论信息

        num = 0                                                 # 已爬取的评论数
        for i in range(1, self.PageNum + 1):                    # 爬取评论
            print('正在爬取第 [' + str(i) + '] 页评论，目前已爬取评论: ' + str(num) + '条.')
            self.updateRequestPayload(self.id, i)                               # 更新post信息即 RequestPayload 成员变量
            html = rq.post(URL, data=json.dumps(self.RequestPayload)).text      # 提交post请求，获取评论信息
            html = json.loads(html)                                             # 将提取到的json对象评论信息转化为python字典
            items = html['result']['items']                                     # 评论信息在items键中
            if items != None:                                                   # 防止出错，即爬取为空的情况
                num += len(items)                                               # 统计评论数
                for x in items:                                                 # 保存评论信息
                    content.append(x['content'])
                    images.append(x['images'])
                    score.append(x['score'])
                    publishTime.append(x['publishTime'])
        self.data = [content, images, score, publishTime]                       # 将评论信息作为列表保存为成员变量data
        return self.data

    def updateRequestPayload(self, id=0, page=1):                               # 更新 post所需要的参数pageIndex、poiId
        self.RequestPayload = {
            'arg': {
                'channelType': 2,
                'collapseType': 0,
                'commentTagId': 0,
                'pageIndex': page,
                'pageSize': 50,
                'poiId': id,
                'sortType': 3,
                'sourceType': 1,
                'starType': 0,
            },
            'head': {
                'auth': '',
                'cid': '09031073114492803259',
                'ctok': "",
                'cver': '1.0',
                'extension': [],
                'lang': "01",
                'sid': '8888',
                'syscode': '09',
                'xsid': '',
            },
        }

    def getId(self, url):           #爬取景区Id
        '''
        作用：返回景区的poiId， 在爬取评论的时候会用到
        :param url:
        :return:
            str -> 该景点页面的对应poiId
        '''
        text = rq.get(url).text                               # 1. 获取 html 页面
        soup = bs(text, 'html.parser')                        # 2. soup 解析html文本
        r = [str(x) for x in soup.select('script')]           # 3. 提取 script 标签， poiId在里面
        return re.findall('poiId":([0-9]+)', ''.join(r))[0]   # 4. 正则表达式 查找后 返回 poiId

    def getCommentNum(self, url):   # 获取评论数
        text = rq.get(url).text                               # 1. 获取 html 页面
        soup = bs(text, 'html.parser')                        # 2. soup 规格化
        r = [str(x) for x in soup.select('.commentModule')]   # 3. 提取标签 查找 评论数
        return re.findall('<!-- -->[(]([0-9]+)[)]', ''.join(r))[0]  # 正则表达式 查找后 返回 CommentNum

    def is_Chinese(self, ch):       # 判断是否为中文字符
        if "\u4e00" <= ch <= '\u9fff':
            return True
        return False

    def WordCount(self):            # 对评论进行词频统计
        result = self.get('https://you.ctrip.com/sight/yandangmountain217/135800.html')[0]   #  获取评论信息中的 评论列表
        result = ''.join(result)                                                             # 将评论列表合并成字符串
        s = jieba.lcut(result)                                                               # lcut将评论里的中文分词
        counts = {}                                                                          # 中文词语词频计数
        for word in s:                                                                       # 遍历分词列表
            if not self.is_Chinese(word) or len(word) <= 1:                                  # 过滤到非中文 或 长度<=1 的字符
                continue
            counts[word] = counts.get(word, 0) + 1

        result = list(counts.items())                                                        # 将词频统计结果字典转化成列表方便排序
        result.sort(key=lambda x: -x[1])                                                     # 根据词语出现次数 进行降序排序
        print('评论前十词频统计:')
        for word, count in result[:10]:                                                      # 输出前十高频词汇
            print(f'内容 [ {word} ] -> 出现次数 [ {count} ] 次')

        pic = plt.imread(r'images/background.jpg')                                           # 加载词频统计图片

        wc = wordcloud.WordCloud(                                                            # 生成图片
            r'c:\windows\fonts\simfang.ttf',
            width=600, height=480,     # 图片大小
            background_color='white',  # 背景颜色
            font_step=5,               # 字体间隔
            mask=pic,                  # 背景图模板
            scale=10,                  # 清晰程度 值越大越清晰
            random_state=False         # check
        )
        t = wc.generate_from_frequencies(dict(result))          # check
        t.to_image().show()                                     # 显示图片